/*
 * Created by Jaren at 2021/10/29 14:13
 */
import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/common/compact.dart';
import 'package:inmotion_protocol/common/mode.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/lorin/bean/base/real_time_info.dart';
import 'package:inmotion_protocol/util/byte_util.dart';

class ScooterAllRealTimeInfo extends AbsAllRealTimeInfo {
  ScooterAllRealTimeInfo(AbsRealTimeInfo realTimeInfo, AbsRealTimeState realTimeState, AbsRealTimeError realTimeError) : super(realTimeInfo, realTimeState, realTimeError);
}

class ScooterRealTimeInfo extends AbsRealTimeInfo {
  Uint32 totalMileage = Uint32.zero;
  Int8 mosTemp = Int8.zero;
  Int8 motorTemp = Int8.zero;
  Int8 batteryTemp = Int8.zero;

  ScooterRealTimeInfo(ProductModel model, VersionWrapper version) : super(model, version);

  @override
  void initCompact() {
    compact = DefaultRealTimeInfoCompact();
  }
}

class DefaultRealTimeInfoCompact extends Compact<ScooterRealTimeInfo> {
  @override
  void fromBytes(ScooterRealTimeInfo output, Uint8ClampedList bytes, int offset) {
    output.voltage = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.current = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.speed = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.mileage = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.remainderRange = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.totalMileage = ByteUtil.bytes2Uint32Le(bytes, offset);
    offset += 4;
    output.batteryLevel = Uint16(ByteUtil.bytes2Uint8Le(bytes, offset).value * 100);
    offset++;
    output.mosTemp = Int8(bytes[offset]);
    offset++;
    output.motorTemp = Int8(bytes[offset]);
    offset++;
    output.batteryTemp = Int8(bytes[offset]);
  }

  @override
  int length() {
    return 18;
  }
}

class ScooterRealTimeState extends AbsRealTimeState {
  Uint4 motorState = Uint4.zero;
  Uint4 brakeState = Uint4.zero;
  Uint4 chargeState = Uint4.zero;
  Uint4 tailLightState = Uint4.zero;
  Uint4 cruiseState = Uint4.zero;

  static const Uint4 pcModeShutdown = Uint4.zero; // 失能（油门刹车无效,车辆显示屏熄灭,对外表现为关机状态）
  static final Uint4 pcModeWorking = Uint4(1); // 使能（油门刹车有效,车辆显示屏工作,车辆可以正常使用）
  static final Uint4 pcModeLock = Uint4(2); // 锁车（车轮抱死,显示屏显示锁车状态）
  static final Uint4 pcModeSleep = Uint4(3); // 休眠（失能，休眠状态下发送任意指令即可唤醒）

  ScooterRealTimeState(ProductModel model, VersionWrapper version) : super(model, version);

  @override
  void initCompact() {
    compact = DefaultRealTimeStateCompact();
  }
}

class DefaultRealTimeStateCompact extends Compact<ScooterRealTimeState> {
  @override
  void fromBytes(ScooterRealTimeState output, Uint8ClampedList bytes, int offset) {
    if (bytes.length < offset + length()) {
      return;
    }
    // 2bit
    output.pcModeValue = ByteUtil.toUint32(ByteUtil.bitValue(bytes[offset], 0, 2).value);
    if (output.pcModeValue.value == 0) {
      output.pcMode = Mode.powerOff;
    } else if (output.pcModeValue.value == 1) {
      output.pcMode = Mode.working;
    } else if (output.pcModeValue.value == 2) {
      output.pcMode = Mode.locked;
    } else if (output.pcModeValue.value == 3) {
      output.pcMode = Mode.sleep;
    }
    output.lockState = Uint4(output.pcMode == Mode.locked ? 1 : 0);
    // 1bit
    output.motorState = ByteUtil.bitValue(bytes[offset], 2, 1);
    // 1bit
    output.brakeState = ByteUtil.bitValue(bytes[offset], 3, 1);
    // 1bit
    output.chargeState = ByteUtil.bitValue(bytes[offset], 4, 1);
    // 1bit
    output.headlightState = ByteUtil.bitValue(bytes[offset], 5, 1);
    // 2bit
    output.tailLightState = ByteUtil.bitValue(bytes[offset], 6, 2);
    offset++;
    // 1bit
    output.cruiseState = ByteUtil.bitValue(bytes[offset], 0, 1);
    // 剩余7bit保留
  }

  @override
  int length() {
    return 2;
  }
}

class ScooterRealTimeError extends AbsRealTimeError {
  static const int underVoltage = 1;
  static const int overVoltage = 2;

  Uint4 breakState = Uint4(0);
  Uint4 throttleState = Uint4(0);
  Uint4 hmicRxState = Uint4(0);
  Uint4 mcRxState = Uint4(0);
  Uint4 mcHeartbeatState = Uint4(0);

  ScooterRealTimeError(ProductModel model, VersionWrapper version) : super(model, version);

  @override
  void initCompact() {
    compact = DefaultRealTimeErrorCompact();
  }

  bool hasVisibleError() {
    return ((originalValue.value << 8) >> 8) == 0;
  }

  bool hasVisibleWarning() {
    return (originalValue.value >> 8) == 0;
  }
}

class DefaultRealTimeErrorCompact extends Compact<ScooterRealTimeError> {
  @override
  void fromBytes(ScooterRealTimeError output, Uint8ClampedList bytes, int offset) {
    if (bytes.length < offset + length()) {
      return;
    }

    output.originalValue = ByteUtil.toInt32(ByteUtil.bytes2Int16Le(bytes).value);

    output.controllerComState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.motorHallState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.batteryState = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.voltageState = ByteUtil.bitValue(bytes[offset], 3, 2);
    output.breakState = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.throttleState = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.hmicRxState = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    output.mcRxState = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.overMosTempState = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.overMotorTempState = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.overBatteryTempState = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.mcHeartbeatState = ByteUtil.bitValue(bytes[offset], 4, 1);
    // 保留3bit
  }

  @override
  int length() {
    return 2;
  }
}
